package cn.wangxl.group.rpc.handler;

import cn.wangxl.group.rpc.discover.ServiceInfoDiscoverer;
import cn.wangxl.group.rpc.exception.RpcNetException;
import cn.wangxl.group.rpc.netclient.NetClient;
import cn.wangxl.group.rpc.protocol.MessageProtocol;
import cn.wangxl.group.rpc.rpcEntity.RpcRequest;
import cn.wangxl.group.rpc.rpcEntity.RpcResponse;
import cn.wangxl.group.rpc.discover.ServiceInfo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * @Deacription ClientStubInvocationHandler
 * @Author 20112128
 * @Date 2020/9/18 10:48
 **/
public class ClientStubInvocationHandler implements InvocationHandler {


    private NetClient netClient;

    private ServiceInfoDiscoverer serviceInfoDiscoverer;

    private Map<String, MessageProtocol> supportMessageProtocols;

    private Class<?> t;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(method.getName().equals("toString")){
            return proxy.getClass().toString();
        }

        if(method.getName().equals("hashCode")){
            return 0;
        }
        // TODO 暂时用接口名 应该从接口注解中获取
        String serviceName = t.getSimpleName();
        List<ServiceInfo> serviceInfos = serviceInfoDiscoverer.getServiceInfo(serviceName);
        if(serviceInfos == null || serviceInfos.size()==0){
            throw new RuntimeException("没有可用的服务");
        }

        // 使用一定的策略选择一个服务
        ServiceInfo serviceInfo = serviceInfos.get(new Random().nextInt(serviceInfos.size()));

        // 组装RPC请求
        RpcRequest rpcRequest = new RpcRequest();

        rpcRequest.setMethod(method.getName());
        rpcRequest.setServiceName(serviceName);
        rpcRequest.setParameterTypes(method.getParameterTypes());
        rpcRequest.setParameters(args);

        MessageProtocol messageProtocol = supportMessageProtocols.get(serviceInfo.getProtocol().getName());
        // 协议层编组
        byte[] sendData = messageProtocol.marshallingRequest(rpcRequest);

        // rpc请求
        byte[] receiveData = netClient.sendRequest(sendData, serviceInfo);

        if(receiveData==null && receiveData.length==0){
            throw new RpcNetException("no rpc response data");
        }
        // 协议层解组
        RpcResponse rpcResponse = messageProtocol.unmarshallingResponse(receiveData);
        if(rpcResponse == null){
            throw new RpcNetException("no rpc response data");
        }
        if(rpcResponse.getException()!=null){
            throw new RuntimeException(rpcResponse.getException());
        }

        return rpcResponse.getReturnValue();
    }

    public ClientStubInvocationHandler(NetClient netClient) {
        this.netClient = netClient;
    }

    public ClientStubInvocationHandler(NetClient netClient,
                                       ServiceInfoDiscoverer serviceInfoDiscoverer,
                                       Map<String, MessageProtocol> supportMessageProtocols) {
        this.netClient = netClient;
        this.serviceInfoDiscoverer = serviceInfoDiscoverer;
        this.supportMessageProtocols = supportMessageProtocols;
    }

    public ClientStubInvocationHandler(NetClient netClient, ServiceInfoDiscoverer serviceInfoDiscoverer, Map<String, MessageProtocol> supportMessageProtocols, Class<?> t) {
        this.netClient = netClient;
        this.serviceInfoDiscoverer = serviceInfoDiscoverer;
        this.supportMessageProtocols = supportMessageProtocols;
        this.t = t;
    }
}
